<html>
    <head>
        <title>概览</title>
    </head>
    <body>
        <script>
            //  ASP.NET Core MVC/Razor Pages：UI主题

                    /*
                        一、导言 Introduction

                                    ABP提供了一个完整的UI主题化系统，其目标如下：

                                            ①、可重用模块的开发是与主题无关的，因此模块可以与任何主题一起使用。

                                            ②、UI主题由最终的宿主应用程序决定。

                                            ③、该主题通过NuGet/NPM包分发，因此易于升级。

                                            ④、最终宿主应用程序可以自定义所选主题。



                                    为了实现这些目标，ABP做了以下工作：

                                            确定所有主题使用和改编的一组基本库。因此，模块和应用程序开发人员可以依赖和使用这些库，而无需依赖于特定主题。

                                            提供一个由导航菜单、工具栏、布局挂钩…组成的系统，由所有主题实现。因此，模块和应用程序为布局做出贡献，以组成一致的应用程序UI。



                                    
                                    1、当前主题  ICurrentTheme

                                               目前，官方提供了四个主题：

                                                    ①、BasicTheme (基本主题) 是具有普通Bootstrap风格的极简主义主题。它是开源和免费的。

                                                    ②、LeptonX Lite主题是现代时尚的Bootstrap UI主题。如果您想拥有一个生产就绪的UI主题，它是理想的选择。它也是开源和免费的。

                                                    ③、Lepton主题是由核心ABP团队开发的商业主题，是ABP许可证的一部分。

                                                    ③、LeptonX主题也是由核心ABP主题开发的商业主题，是ABP许可证的一部分。这是ABP v6.0.0之后的默认主题。


                                        ABP也有一些社区驱动的主题（您可以在网络上搜索）。
                    */

                    /*
                        二、总体概览  OverAll

                              1、主题通用前端基础库

                                                    所有主题都必须依赖于 " @abp/aspnetcore.mvc.ui.theme.shared" 共享NPM包，因此它们间接依赖于以下库：

                                                        ①、Twitter Bootstrap作为基本的超文本标记语言/CSS框架。

                                                        ②、 用于DOM操作的JQuery。

                                                        ③、 DataTables.Net用于数据网格。

                                                        ④、JQuery Validation  用于客户端的JQuery验证和静默的验证

                                                        ⑤、FontAwese作为基本的CSS字体库。

                                                        ⑥、SweetAlert显示精美的警报消息和确认对话框。

                                                        ⑦、 Toastr显示通知。(Toast)

                                                        ⑧、 Lodash作为实用工具库

                                                        ⑨、Luxon用于日期/时间操作。

                                                        ⑩、 用于AJAX表单的JQuery Form

                                                        ⑫、bootstrap-datepicker显示日期选择器。

                                                        ⑬、Select2  选择框、多选框

                                                        ⑭、Timeago显示自动更新的模糊时间戳。

                                                        ⑮、malihu-custom-scrollbar-plugin用于自定义滚动条。

                                                    这些库被选为基础库，可供应用程序和模块使用。


                              2、对基础库的抽象和包装    Abstractions / Wrappers

                                             ABP中有一些抽象，可以使您的代码也独立于其中一些库。
                                             
                                                       ①、Tag Helpers可以轻松生成Bootstrap UI。

                                                       ②、JavaScriptMessage和NotifyAPI提供了使用Sweet警报和Toastr的抽象。

                                                       ③、Forms&Valiri系统会自动处理验证，因此您大多不会直接键入任何验证代码。



                              3、标准布局  The Standard Layouts

                                             主题的主要职责是提供布局。有三个预定义的布局必须由所有主题实现：

                                                ①、Application：主应用程序页面使用的默认布局。

                                                ②、Account:  主要由帐户模块用于登录、注册、忘记密码…页面。、

                                                ③、Empty: 根本没有布局组件的最小布局。

                                            布局名称是在Volo.Abp.AspNetCore.Mvc.UI.Theming.StandardLayouts类中定义的常量。

                                            (1)、应用程序布局  Application Layout

                                                    这是主应用程序页面使用的默认布局。下图显示了基本主题应用程序布局中的用户管理页面：

                                                    如您所见，页面是相同的，但在上面的主题中外观完全不同。

                                                    应用程序布局通常包括以下部分:

                                                        ①、主菜单 A main menu

                                                        ②、主工具ToolBar栏包含以下组件：

                                                                用户菜单   User Menu

                                                                语言切换下拉列表  Language Switch Dropdown

                                                        ③、页面提醒 page alerts

                                                        ④、页面内容（又名RenderBody()）

                                                        ⑤、布局挂钩 Layout hooks

                                                    一些主题可能会提供更多部分，例如面包屑、页眉和工具栏…等。请参阅布局部件部分。



                                            (2)、账户布局 Account Layout

                                                    帐户布局通常由帐户模块用于登录、注册、忘记密码…页面。

                                                    此布局通常提供以下部分:

                                                            ①、语言切换下拉列表

                                                            ②、租户切换区域（如果应用程序是多租户并且当前由cookie解析）

                                                            ③、页面提醒 Page alerts 

                                                            ④、页面内容（又名RenderBody()

                                                            ⑤、布局挂钩 Layout hooks 

                                                    基本主题也呈现此布局的顶部导航栏（如上所示）


                                            (3)、空布局 Empty Layout

                                                    空布局提供一个空页面。它通常包括以下部分：

                                                            ①、Page alerts 页面提醒

                                                            ②、页面内容（又名RenderBody()

                                                            ③、Layout hooks 布局挂钩
                    */

                    /*
                        二、实现一个主题   Implementing a Theme

                                1、最简单的方法

                                        创建新主题的最简单方法是添加带有源代码的基本主题源代码模块并对其进行自定义。

                                            "abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic --with-source-code --add-to-solution-file"



                                2、ITheme接口 

                                        ITheme接口由ABP用于选择当前页面的布局。

                                        主题必须实现此接口才能提供请求的布局路径。

                                        这是基本主题(Basic)的ITheme实现

                                                using Volo.Abp.AspNetCore.Mvc.UI.Theming;
                                                using Volo.Abp.DependencyInjection;

                                                namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
                                                {
                                                        [ThemeName(Name)]  // 此特性是必须有的，并且主题必须在此示例中具有唯一名称 "Basic"
                                                        public class BasicTheme : ITheme, ITransientDependency
                                                        {
                                                                public const string Name = "Basic";  

                                                                public virtual string GetLayout(string name, bool fallbackToDefault = true)
                                                                {
                                                                        switch (name)  // 根据主题名称，返回布局视图路径
                                                                        {
                                                                                case StandardLayouts.Application:
                                                                                        return "~/Themes/Basic/Layouts/Application.cshtml";

                                                                                case StandardLayouts.Account:
                                                                                        return "~/Themes/Basic/Layouts/Account.cshtml";

                                                                                case StandardLayouts.Empty:
                                                                                        return "~/Themes/Basic/Layouts/Empty.cshtml";

                                                                                default:
                                                                                        return fallbackToDefault
                                                                                                ? "~/Themes/Basic/Layouts/Application.cshtml"
                                                                                                : null;
                                                                        }
                                                                }
                                                        }
                                                }

                                                [ThemeName] 特性是必须的，并且主题必须在此示例中具有唯一性名称 "Basic".

                                                GetLayout 方法返回路径。如果主题旨在又标准应用程序使用，则应该实现标准布局。它可以实现额外的布局。


                                        一旦主题实现了 ITheme 接口，它应应该将主题添加到模块的 ConfigureService 方法中的 AbpThemingOptions.

                                                Configure<AbpThemingOptions>(options =>
                                                {
                                                        options.Themes.Add<BasicTheme>();  // 在模块类中注册主题
                                                });
                                       
                                                


                                                ★、、IThemeSelector服务  

                                                        ABP允许同时使用多个主题，这就是为什么options.Themes是一个列表。

                                                        IThemeSelector服务在运行时选择主题。

                                                        应用程序开发人员可以设置AbpThemingOptions.DefaultThemeName来设置要使用的主题，

                                                        或者替换IThemeSelector服务实现（默认实现为DefaultThemeSelector）来完全控制运行时的主题选择。
                                                  
                                                        
                                3、捆绑  Bundles

                                               捆绑系统提供了一种将"样式"和"脚本"文件导入页面的标准方法。

                                               ABP 定义了两个标准包：

                                                        ①、StandardBundles.Styles.Global：包含所有页面中使用的样式文件的全局包。

                                                                                          通常，它包括基本库的CSS文件。

                                                        ②、StandardBundles.Scripts.Global：包含所有页面中使用的脚本文件的全局包。
                                                                        
                                                                                           通常，它包括基本库的JavaScript文件。

                                                主题通常通过添加特定于主题的CSS、JavaScrpit 文件来扩展这些标准包、

                                                定义新的捆绑包、从标准捆绑包继承并添加到AbpBundlingOptions 的最佳方法如下所示(此代码来自 Basic 主题)：

                                                        Configure<AbpBundlingOptions>(options =>
                                                        {
                                                                options
                                                                        .StyleBundles
                                                                        .Add(BasicThemeBundles.Styles.Global, bundle =>
                                                                        {
                                                                        bundle
                                                                                .AddBaseBundles(StandardBundles.Styles.Global)
                                                                                .AddContributors(typeof(BasicThemeGlobalStyleContributor));
                                                                        });

                                                                options
                                                                        .ScriptBundles
                                                                        .Add(BasicThemeBundles.Scripts.Global, bundle =>
                                                                        {
                                                                        bundle
                                                                                .AddBaseBundles(StandardBundles.Scripts.Global)
                                                                                .AddContributors(typeof(BasicThemeGlobalScriptContributor));
                                                                        });
                                                        });

                                            
                                                BasicThemeGlobalStyleContributor和BasicThemeGlobalScriptContributor是包贡献者。
                                                
                                                例如，BasicThemeGlobalStyleContributor定义如下：

                                                        // 捆绑包贡献者
                                                        public class BasicThemeGlobalStyleContributor : BundleContributor
                                                        {
                                                                public override void ConfigureBundle(BundleConfigurationContext context)
                                                                {
                                                                        context.Files.Add("/themes/basic/layout.css");
                                                                }
                                                        }


                                                然后主题可以在布局中呈现这些包。例如，您可以呈现全局样式，如下所示：

                                                        <abp-style-bundle name="@BasicThemeBundles.Styles.Global" />




                                4、布局零件  Layout Parts 

                                                一个典型的布局由几个部分组成。主题应该包括么个布局中必要的部分。

                                                eg: 基本主题具有应用程序布局的以下部分：


                                                应用程序代码和模块只能显示页面内容部分的内容。

                                                如果他们需要更改其他部分 (添加菜单项、添加工具栏项、更改品牌区域中的应用程序名称)，应该使用ABP Api。



                                                以下部分解释了ABP预先定义的基本部分，并且可以通过主题实现。

                                                (1)、品牌化  Branding

                                                        IBrandingProvider服务应用于获取要在品牌部分呈现的应用程序的名称和徽标URL。

                                                        Application Startup Template有一个此接口的实现，用于由应用程序开发人员设置值。
                                                        

                                                (2)、主菜单  Main Menu

                                                         IMenuManager服务用于获取主菜单项并在布局上呈现。

                                                         eg:  获取要在视图组件中呈现的主菜单

                                                                // 主菜单视图组件
                                                                public class MainNavbarMenuViewComponent : AbpViewComponent
                                                                {
                                                                        private readonly IMenuManager _menuManager;

                                                                        public MainNavbarMenuViewComponent(IMenuManager menuManager)
                                                                        {
                                                                                _menuManager = menuManager; // 注入菜单管理器
                                                                        }

                                                                        public async Task<IViewComponentResult> InvokeAsync()
                                                                        {
                                                                                var menu = await _menuManager.GetAsync(StandardMenus.Main);
                                                                                return View("~/Themes/Basic/Components/Menu/Default.cshtml", menu);
                                                                        }
                                                                }

                                                         请参阅导航/菜单文档以了解有关导航系统的更多信息。

                                                (3)、主工具栏  Main ToolBar

                                                          IToolbarManager服务用于获取主工具栏项目并在布局上呈现。

                                                          此工具栏的每个项目都是一个视图组件，因此它可能包含任何类型的UI元素。
                                                          
                                                          注入IToolbarManager并使用GetAsync获取工具栏项目：

                                                                var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main);

                                                          该主题有责任将两个预定义的项目添加到主工具栏：语言选择和用户菜单。

                                                          为此，请创建一个实现IToolbarContributor接口的类并将其添加到AbpToolbarOptions，如下所示：

                                                                Configure<AbpToolbarOptions>(options =>
                                                                {
                                                                        options.Contributors.Add(new BasicThemeMainTopToolbarContributor());
                                                                });

                                                           ①、 语言选择  Language Selection

                                                                   语言选择工具栏项通常是用于在语言之间切换的下拉列表。
                                                                   
                                                                   ILanguageProvider用于获取可用语言列表，CultureInfo.CurrentUICulture用于学习当前语言。

                                                                   /Abp/Languages/Switch端点可用于切换语言此端点接受以下查询字符串参数：

                                                                        culture：选定的区域性，如en-US或en。

                                                                        uiCulture：选定的UI文化，如en-US或en。

                                                                        returnUrl（可选）：可用于切换语言后返回给定的URL。

                                                                   culture和uiCulture应匹配可用语言之一。ABP在/Abp/Languages/Switch端点中设置文化cookie。


                                                            ②、用户菜单  
                                                                     
                                                                    用户菜单包括与用户帐户相关的链接。
                                                                    
                                                                    IMenuManager与主菜单一样使用，但这次使用StandardMenus.User参数，如下所示：

                                                                        var menu = await _menuManager.GetAsync(StandardMenus.User);

                                                                     ICurrentUser和ICurrent租户服务可用于获取当前用户和租户名称。

                                                (4)、页面提醒  Page Alerts

                                                            IAlertManager服务用于获取要在布局上呈现的当前页面警报。

                                                            使用IAlertManager的Alerts列表。

                                                            它通常在页面内容之前呈现（RenderBody()）。


                                                (5)、布局挂钩  Layout Hooks

                                                             由于Layout在主题包中，因此最终应用程序或任何模块都不能直接操作布局内容。

                                                             Layout Hook系统允许将组件注入布局的某些特定点。

                                                             主题负责在正确的位置渲染钩子。

                                                             eg： 在应用程序布局中呈现LayoutHooks.Head.First钩子

                                                                    <head>
                                                                        @await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Application)
                                                                        ... 
                                                        
                                                (6)、脚本、样式   Script / Style Sections

                                                             每个布局都应呈现以下可选部分：

                                                                        styles部分呈现在head的末尾，就在LayoutHooks.Head.Last之前。

                                                                        scripts部分呈现在body的末尾，就在LayoutHooks.Body.Last之前。

                                                              这样，页面就可以将样式和脚本导入到布局中。
                                                                        
                                                                        eg:  呈现styles部分
                                                                        
                                                                        @await RenderSectionAsync("styles", required: false)

                                                (7)、内容工具栏 

                                                             另一个预定义的部分是Content Toolbar部分，页面可以使用它在页面内容之前添加代码。

                                                             基本主题呈现如下所示：

                                                                        <div id="AbpContentToolbar">
                                                                                <div class="text-end mb-2">
                                                                                        @RenderSection("content_toolbar", false)
                                                                                </div>
                                                                        </div>  

                                                              容器div的id必须是AbpContentToolbar。此部分应位于RenderBody()之前。


                                                (8)、小部件资源  Widget Resourse 

                                                              Widget System允许使用自己的样式/脚本文件定义可重用的小部件。
                                                              
                                                              所有布局都应呈现小部件样式和脚本。

                                                              小部件样式呈现如下所示，就在styles部分之前，在全局样式包之后：

                                                                       @await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
                                                                       
                                                              小部件脚本呈现如下所示，就在scripts部分之前，在全局脚本包之后：

                                                                        @await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))

                                                (9)、ABP  Script  

                                                              ABP有一些特殊的脚本，应该包含在每个布局中。它们不包含在全局包中，因为它们是根据当前用户动态创建的。

                                                              ABP脚本（ApplicationConfigurationScript和ServiceProxyScript）应该在全局脚本包之后添加，如下所示：

                                                                      <script src="~/Abp/ApplicationConfigurationScript"><//script>
                                                                      < src="~/Abp/ServiceProxyScript"><//script>  

                                                (10)、页面标题、选定的菜单项和面包屑

                                                               IPageLayout服务可以被任何页面注入以设置页面标题、选定的菜单项名称和面包屑项。
                                                               
                                                               然后主题可以使用此服务获取这些值并在UI上呈现。

                                                               基本主题没有实现此服务，但Lepton主题实现了：


                                                (11)、租户切换

                                                                
                                                                如果应用程序是多租户并且租户是从cookie中解析的，则帐户布局应允许用户切换当前租户。请参阅基本主题帐户布局作为示例实现。


                                5、布局类  Layout Classes
                                
                                                标准布局（Application、Account和Empty）应将以下CSS类添加到body标记中：

                                                      ①、abp-application-layout用于Application布局。

                                                      ②、abp-account-layout 用于 Account布局

                                                      ③、abp-empty-layout用于Empty布局。


                                6、NPM包  

                                                主题应该有一个NPM包，它依赖于@abp/aspnetcore. mvc.ui.theme。shared。
                                                
                                                通过这种方式，它继承了所有基库。如果主题需要额外的库，那么它也应该定义这些依赖项。 

                                                应用程序使用Client Side Package Management系统向项目添加客户端库。

                                                因此，如果应用程序使用您的主题，它应该向您的主题的NPM包和NuGet包依赖项添加依赖项。



                                                              
                                                             
                                                             




                                                
                                
                                                

                                                        

                    */
        </script>
    </body>
</html>     